#include "stdint.h"
#include "stdbool.h"
#include "pt_config.h"
#include "workqueue.h"
#include "pt_god_schedule.h"
#include "ptdebug.h"
struct pt sys_workq_thread;

struct pt_workqueue sys_workq = {
    .work_list.next = &sys_workq.work_list,
    .work_list.prev = &sys_workq.work_list,
    .work_current   = PT_NULL,
    .work_thread    = &sys_workq_thread,
};

#define PT_WORKQUEUE_DBG_LVL    PT_LOG_LEVEL_KERNEL

#ifdef PT_USING_WORKQUEUE

#ifdef __CC_ARM
#pragma diag_suppress 111
#endif

static PT_THREAD( _workqueue_thread_entry(struct pt *pt) )
{
    bool work_done = false;
    PT_BEGIN ( pt );

    static struct pt_work *work;
    static struct pt_workqueue *queue;

    static pt_list_t *next_work_tmp;    //当前工作的下一个工作

    queue = (struct pt_workqueue *) &sys_workq;

    while (1){
        //工作队列空
        if (pt_list_isempty(&(queue->work_list))){
            PT_SUSPEND(pt); //队列空挂起自己
        }

        /* we have work to do with. */
        pt_hw_interrupt_disable();

//        work = pt_list_entry(queue->work_list.next, struct pt_work, list);

        // 还没有工作或者轮询到自己了, 自己挂在上面但却不是工作, 直接指向下一个,
        // 系统工作队列sys_workq只是一个链表头
        if(PT_NULL == queue->work_current || queue->work_current == (struct pt_work *)&sys_workq){
            queue->work_current = pt_list_entry(queue->work_list.next, struct pt_work, list);
        }
        work = queue->work_current;
        next_work_tmp = work->list.next;

        pt_hw_interrupt_enable();

        // 执行工作
        if(work->work_func != PT_NULL &&            // 工作绑定了回调函数
           work->flags & PT_WORK_STATE_PENDING){    // 工作已提交

            if( work->timer.flag & PT_TIMER_FLAG_ACTIVATED ){   //若定时器激活需超时再调用
                if( timer_expired(&work->timer) ){              //超时后调用
                    work->timer.flag &= ~PT_TIMER_FLAG_ACTIVATED;
                    work->work_func(work);
                    work_done = true;
                }

            }else{
                work->work_func(work);
                work_done = true;
                if(work->type & PT_WORK_TYPE_SOON){     // 尽快执行的工作, 执行第一次后将定时器激活
                    work->type &= ~PT_WORK_TYPE_SOON;   // 就变成普通的工作
                    work->timer.flag |= PT_TIMER_FLAG_ACTIVATED;
                }
            }

        }

        // 工作已执行
        if (work_done){
            // 不是重复执行的工作, 则移除
            if( !(work->type & PT_WORK_TYPE_REPEAT) ){
                pt_list_remove(&(work->list));
                work->flags &= ~PT_WORK_STATE_PENDING;
            }else{
                timer_set(&work->timer, work->timer.interval );  // 重新设置定时
                work->timer.flag |= PT_TIMER_FLAG_ACTIVATED;

                if(work->do_times < 0xFFFFF0){   // 如果设置的值大于它, 那么就永久执行了, 次数不减少
                    work->do_times--;
                }

                // 执行完了设定的次数则移除
                if(work->do_times < 1){
                    pt_list_remove(&(work->list));
                    work->flags &= ~PT_WORK_STATE_PENDING;
                }
            }
        }


//_next_work:
        pt_hw_interrupt_disable();

        //指向下一个工作
        queue->work_current = pt_list_entry(next_work_tmp, struct pt_work, list);
        pt_hw_interrupt_enable();

        PT_YIELD(pt);   //每执行完一个工作都让出CPU
    }

    PT_END( pt );
}
/*
 *@description: 系统工作队列初始化, 在系统开始处调用, 例如放入submain
 *@param: NA
 *@return: NA
 *@author: Kalimdorsummer
 *@date: 2020-04-18 10:42:36
*/
int pt_work_sys_workqueue_init(void)
{
    //初始化系统工作队列线程后, 就会被后台调度
    pt_thread_init(&sys_workq_thread, _workqueue_thread_entry);
    return PT_EOK;
}
/*
 *@description: 提交工作到系统工作队列
 *@param: work, 要提交的工作
 *@return: NA
 *@author: Kalimdorsummer
 *@date: 2020-04-18 10:43:36
*/
int32_t pt_schedule_work(struct pt_work *work)
{
    if( sys_workq_thread.alive != PT_PROCESS_ALIVE){
        PT_DEBUG_LOG(PT_WORKQUEUE_DBG_LVL, ( "WARNIGN: sys_workq_thread not init\n" ) )     ;
    }

    //已经提交了工作
    if (work->flags & PT_WORK_STATE_PENDING){
        return -PT_EBUSY;
    }

    if (sys_workq.work_current == work){
        return -PT_EBUSY;
    }

    work->flags |= PT_WORK_STATE_PENDING;    //提交工作任务

    //将新工作插入到系统工作队列尾部
    pt_list_insert_before( &(sys_workq.work_list), &(work->list) );
    PT_RESUME(&sys_workq_thread);       //恢复系统工作队列线程

    return PT_EOK;
}

/*
 *@description: 提交延迟的工作到系统工作队列
 *@param: work, 要提交的工作, ticks, 延迟的滴答数
 *@return: NA
 *@author: Kalimdorsummer
 *@date: 2020-04-18 10:44:36
*/
int32_t pt_schedule_delayed_work(struct pt_work *work, uint32_t ticks)
{
    int32_t res;
    res = pt_schedule_work(work);

    timer_set(&work->timer, ticks);     //设置定时时间, 在系统工作队列线程中判断超时
    work->timer.flag |= PT_TIMER_FLAG_ACTIVATED;    //设置为激活

    return res;
}
/*
 *@description: 提交延迟的工作到系统工作队列
 *@param: work, 要提交的工作, time, 延迟的滴ms数
 *@return: NA
 *@author: Kalimdorsummer
 *@date: 2020-04-18 10:44:36
*/
int32_t pt_schedule_delayed_ms_work(struct pt_work *work, uint32_t time)
{
    return pt_schedule_delayed_work(work, MS_TO_TICK(time) );
}

/*
 *@description: 提交重复执行的工作
 *@param: work, 要提交的工作, ms, 重复执行的间隔, cnt, 重复执行的次数, cnt > 0XFFFFF0 则永久执行
 *@return: NA
 *@author: Kalimdorsummer
 *@date: 2020-05-17 17:56:26
*/
int32_t pt_schedule_repeat_work(struct pt_work *work, uint32_t ms, uint32_t cnt)
{
    int32_t res;
    res = pt_schedule_work(work);

    work->type |= PT_WORK_TYPE_REPEAT;      // 重复执行的工作
    work->type &= ~PT_WORK_TYPE_SOON;       // 普通执行, 即第一次就延时
    work->do_times = cnt;                   // 执行次数

    timer_set( &work->timer, MS_TO_TICK(ms) );     //设置定时时间, 在系统工作队列线程中判断超时
    work->timer.flag |= PT_TIMER_FLAG_ACTIVATED;  //设置为激活


    return res;
}

/*
 *@description: 提交重复执行的工作, 第一次尽快执行
 *@param: work, 要提交的工作, ms, 重复执行的间隔, cnt, 重复执行的次数
 *@return: NA
 *@author: Kalimdorsummer
 *@date: 2020-05-17 16:57:22
*/
int32_t pt_schedule_repeat_work_soon(struct pt_work *work, uint32_t ms, uint32_t cnt)
{
    int32_t res;
    res = pt_schedule_work(work);

    work->type |= PT_WORK_TYPE_REPEAT;  // 重复执行的工作
    work->type |= PT_WORK_TYPE_SOON;    // 第一次尽快执行
    work->do_times = cnt;               // 执行次数

    timer_set( &work->timer, MS_TO_TICK(ms) );     //设置定时时间, 在系统工作队列线程中判断超时
    work->timer.flag &= ~PT_TIMER_FLAG_ACTIVATED;  //设置为不激活, 因为第一次要尽快执行


    return res;
}

/*
 *@description: 绑定工作和工作的回调函数
 *@param: work, 工作, work_func, 工作的回调函数
 *@return: NA
 *@author: Kalimdorsummer
 *@date: 2020-04-18 10:44:36
*/
void pt_work_bind_func(struct pt_work *work, void (*work_func)(struct pt_work *) )
{
    work->work_func = work_func;
}

/*
 *@description: 传递参数到工作中, 例如在中断回调中需要传递参数到下半部则调用它
 *@param: work, 工作, work_data, 传递的数据指针(也可以是数据本身), work_data_len,数据长度; 由应用程序决定是否使用
 *@return: NA
 *@author: Kalimdorsummer
 *@date: 2020-04-18 10:45:56
*/
void pt_work_forward_param(struct pt_work *work, void *work_data, uint32_t work_data_len)
{
    work->work_data     = work_data;
    work->work_data_len = work_data_len;
}

/*
 *@description: 取消一个工作
 *@param: work, 工作
 *@return: NA
 *@author: Kalimdorsummer
 *@date: 2020-05-17 18:04:46
*/
void pt_work_cancel(struct pt_work *work)
{
    pt_list_remove(&(work->list));
    work->flags &= ~PT_WORK_STATE_PENDING;
}

int32_t pt_work_state(struct pt_work *work)
{
    //已经提交了工作
    if (work->flags & PT_WORK_STATE_PENDING){
        return -PT_EBUSY;
    }

    if (sys_workq.work_current == work){
        return -PT_EBUSY;
    }

    return PT_EOK;
}

#endif
